package com.hong.listener.impl;

import com.hong.Config.RegisterConfig;
import com.hong.Config.RpcServerConfig;
import com.hong.RpcServer;
import com.hong.ServiceManager;
import com.hong.listener.Listener;
import com.hong.listener.ListenerManager;
import com.hong.listener.RpcServerListener;
import com.hong.qrpc.annotation.QRpcClient;
import com.hong.qrpc.annotation.Service;
import com.hong.qrpc.pojo.RegisterCenterConfig;
import com.hong.qrpc.register.Register;
import com.hong.qrpc.utils.ReflectionUtils;
import com.hong.qrpc.utils.StringUtils;
import com.hong.vo.ListenerCandidate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Map;

/**
 * 用于进行服务暴露的类
 *
 * @Author HQT
 * @Date 2022/7/22 19:57
 */
@Slf4j
public class Registrar implements RpcServerListener {
    //TODO 这种方式不具有普适性，有待改进
    /**
     * 因为要将其存进set中去重，并且我们只需要set中只有一个该类实例对象，所以为了便于set的判重，所以选用这个字段代表这个类
     */
    private String helpCompare = "com.hong.listener.impl.Registrar";
    private String scanPackageUrls;
    private boolean needExport = true;
    private ServiceManager serviceManager;
    private Register register;
    private RegisterConfig registerConfig;
    private RpcServerConfig rpcServerConfig;
    private RpcServer rpcServer;

    @Override
    public void beforeRpcServerStart(RpcServer rpcServer) {
        this.rpcServer = rpcServer;
        if (scanPackageUrls != null && !rpcServer.getConfigManager().getRegisterConfig().isStartBySpring()) {
            registerConfig = rpcServer.getConfigManager().getRegisterConfig();
            serviceManager = rpcServer.getServiceManager();
            register = rpcServer.getRegister();
            rpcServerConfig = rpcServer.getConfigManager().getRpcServerConfig();
            try {
                register(scanPackageUrls);
            } catch (Exception e) {
                log.error("register error");
            }
        }
    }

    private void register(String packageUrls) throws IOException {
        for (String packageUrl : packageUrls.split(";")) {
            packageUrl = StringUtils.replaceAll('.', '/', packageUrl);
            packageUrl = StringUtils.replaceAll('\\', '/', packageUrl);
            registerFromPackage(packageUrl);
        }
    }

    /**
     * 获取用户需要扫描的路径下的所有class，并加载有QRpcClient注解的类
     *
     * @param path
     * @throws IOException
     */
    private void registerFromPackage(String path) throws IOException {
        path = getPatternPath(path);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resolver.getResources(path);
        for (Resource resource : resources) {
            String classPath = resource.getURL().getPath();
            int idx = classPath.indexOf("/classes/");
            if (idx == -1) {
                continue;
            }
            String className = StringUtils.replaceAll('/', '.',
                    classPath.substring(idx + "/classes/".length(), classPath.length() - ".class".length()));
            try {
                Class clazz = Class.forName(className);
                registerService(clazz);
            } catch (Exception e) {
                //加载到某些第三方的类可能会出现异常，此处不作处理
                log.debug("loaded class:" + className + "  fail");
            }
        }
    }

    private void registerService(Class clazz) throws UnknownHostException {
        QRpcClient annotation = null;
        if ((annotation = (QRpcClient) clazz.getAnnotation(QRpcClient.class)) != null) {
            //检查是否需要对外暴露服务
            if (needExport && register != null) {
                InetAddress addr = InetAddress.getLocalHost();
                String serverIp = addr.getHostAddress();
                //切分获取所有注册中心的地址然后进行注册
                String registerAddrs = registerConfig.getRegisterAddrs();
                //添加需要注册到注册中心的类让监听器注册类
                NacosRegister nacosRegister = new NacosRegister(register);
                for (String registerAddr : StringUtils.splitByChars(registerAddrs, ';')) {
                    RegisterCenterConfig registerCenterConfig = new RegisterCenterConfig(
                            registerAddr, serverIp, rpcServerConfig.getPort(), annotation.serviceName()
                    );
                    nacosRegister.addRegisterCenterConfig(registerCenterConfig);
                }
                addListener(nacosRegister);
            }
        }
        Service anno = null;
        if ((anno = (Service) clazz.getAnnotation(Service.class)) != null) {
            register(clazz.getInterfaces()[0], ReflectionUtils.newInstance(clazz));
        }
    }

    private void addListener(NacosRegister nacosRegister) {
        rpcServer.getListenerCandidates().add(new ListenerCandidate(RpcServerListener.class, nacosRegister));
    }

    /**
     * 将用户的输入路径处理成正确的模式串
     *
     * @param path
     * @return
     */
    private String getPatternPath(String path) {
        path = StringUtils.replaceAll('.', '/', path);
        if (path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }
        StringBuilder sb = new StringBuilder().append("classpath*:").append(path);
        if (path.endsWith("/**")) {
            sb.append("/*.class");
        } else if (path.endsWith("/*")) {
            sb.append("/*.class");
        } else {
            sb.append("/**/*.class");
        }
        return sb.toString();
    }

    /**
     * 递归地去寻找需要加载的服务实例对象
     */
//    private void registerFromPackage(File curFile, Deque<String> subUrls) {
//        if (curFile.isFile()) {
//            String curPath = curFile.getPath();
//            if (curPath.endsWith(".class")) {
//                try {
//                    Class clazz = Class.forName(StringUtils.getClassName(subUrls));
//                    QRpcClient annotation = null;
//                    if ((annotation = (QRpcClient) clazz.getAnnotation(QRpcClient.class)) != null) {
//                        //检查是否需要对外暴露服务
//                        if (needExport && register != null) {
//                            InetAddress addr = InetAddress.getLocalHost();
//                            String serverIp = addr.getHostAddress();
//                            //切分获取所有注册中心的地址然后进行注册
//                            String registerAddrs = registerConfig.getRegisterAddrs();
//                            for (String registerAddr : StringUtils.splitByChars(registerAddrs, ';')) {
//                                RegisterCenterConfig registerCenterConfig = new RegisterCenterConfig(
//                                        registerAddr, serverIp, rpcServerConfig.getPort(), annotation.serviceName()
//                                );
//                                register.registerService(registerCenterConfig);
//                            }
//                        }
//                    }
//                    Service anno = null;
//                    if ((anno = (Service) clazz.getAnnotation(Service.class)) != null) {
//                        register(clazz.getInterfaces()[0], ReflectionUtils.newInstance(clazz));
//                    }
//                } catch (ClassNotFoundException e) {
//                    e.printStackTrace();
//                } catch (UnknownHostException e) {
//                    e.printStackTrace();
//                }
//            }
//        } else {
//            for (String subUrl : curFile.list()) {
//                subUrls.addLast(subUrl);
//                registerFromPackage(new File(curFile, subUrl), subUrls);
//                subUrls.removeLast();
//            }
//        }
//    }
    public <T> void register(Class<T> interfaceClass, T bean) {
        serviceManager.register(interfaceClass, bean);
    }

    public static Registrar addListener(ListenerManager listenerManager) {
        Map<Class<? extends Listener>, HashSet<Listener>> listenerSets = listenerManager.getListenerSets();
        HashSet<Listener> listeners = listenerSets.get(RpcServerListener.class);
        if (listeners == null) {
            listeners = new HashSet<>();
            listenerSets.put(RpcServerListener.class, listeners);
        }
        Registrar rs = new Registrar();
        if (!listeners.contains(rs)) {
            listeners.add(rs);
        } else {
            //获取set集合中的监听器
            for (Listener listener : listeners) {
                if (rs.equals(listener)) {
                    rs = (Registrar) listener;
                }
            }
        }
        return rs;
    }

    public String getScanPackageUrls() {
        return scanPackageUrls;
    }

    public boolean isNeedExport() {
        return needExport;
    }

    public void setNeedExport(boolean needExport) {
        this.needExport = needExport;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Registrar registrar = (Registrar) o;

        return helpCompare.equals(registrar.helpCompare);
    }

    @Override
    public int hashCode() {
        return helpCompare.hashCode();
    }

    public void setScanPackageUrls(String scanPackageUrls) {
        this.scanPackageUrls = scanPackageUrls;
    }
}
